<script setup lang="ts">
import { computed, nextTick, ref, watch } from "vue";
import {
  BaseSaleAttr,
  SpuData,
  SpuDetail,
  SpuImage,
  SpuSaleAttr,
  Trademark,
} from "@/api/product/spu/type.ts";
import {
  reqAddOrUpdateSpu,
  reqBaseSaleAttrList,
  reqSpuImageList,
  reqTrademarkList,
  rqeSpuSaleAttrList,
} from "@/api/product/spu";
import { ElInput, ElMessage, UploadProps, UploadUserFile } from "element-plus";

// 引入自定义事件
let $emit = defineEmits(["updateScene"]);

let spuParams = ref<SpuDetail>({
  category3Id: 0, // 三级分类id
  spuName: "", // spu名称
  description: "", // spu描述
  tmId: 0, // 品牌id
  spuImageList: [], // spu图片列表
  spuSaleAttrList: [], // spu销售属性列表
});

let allTrademarkList = ref<Trademark[]>([]); // 所有品牌列表

let imageList = ref<SpuImage[]>([]); // spu图片列表

let hasAttrList = ref<SpuSaleAttr[]>([]); // 已经添加的销售属性列表

let attrListAll = ref<BaseSaleAttr[]>([]); // 所有销售属性列表

// 提交
const submit = async () => {
  //1. 整理数据
  // 1.1 整理spu的图片列表
  spuParams.value.spuImageList = fileList.value.map((item) => {
    return {
      // 如果item.response有值  就用item.response  如果没有值 就用item.url
      imgUrl: item.response?.data || item.url,
      imgName: item.name,
      // spuId: spuParams.value.id,
    };
  });
  // 1.2 整理spu的销售属性列表
  spuParams.value.spuSaleAttrList = hasAttrList.value.map((item) => {
    return {
      baseSaleAttrId: item.baseSaleAttrId || item.saleAttrId,
      saleAttrName: item.saleAttrName,
      spuId: spuParams.value.id,
      spuSaleAttrValueList: item.spuSaleAttrValueList,
    };
  });
  // 2. 发送请求
  let result = await reqAddOrUpdateSpu(spuParams.value);
  if (result.code === 200) {
    // 通知父组件切换场景
    $emit("updateScene", 0, !spuParams.value.id);
    ElMessage.success("操作成功");
    // 清空添加spu的表单
    resetParams();
  } else {
    ElMessage.error("操作失败");
  }
};

// 清空添加spu的表单
const resetParams = () => {
  allTrademarkList.value = [];
  imageList.value = [];
  hasAttrList.value = [];
  attrListAll.value = [];
  fileList.value = [];
  spuParams.value = {
    category3Id: 0, // 三级分类id
    spuName: "", // spu名称
    description: "", // spu描述
    tmId: 0, // 品牌id
    spuImageList: [], // spu图片列表
    spuSaleAttrList: [], // spu销售属性列表
  };
};

// 取消
const cancel = () => {
  // 清空添加spu的表单
  resetParams();
  // 通知父组件切换场景
  $emit("updateScene", 0);
};

// 初始化数据
const initData = async (row: SpuData) => {
  // 如果row.id有值  就是修改  如果没有值  就是添加
  if (row.id) {
    // 将前一个页面传递过来的数据赋值给spuParams  这个spuParams就是我们在表单中v-model绑定的数据
    spuParams.value = row;
    await getTrademarkList();
    // 这个地方定义SpuData 定义id为？ id就有可能是undefined或者number  我们在修改的时候一定有id 所以我们断言id为number
    await getSpuImageList(row.id as number);
    await getSpuSaleAttrList(row.id as number);
    await getSaleAttrListAll();
  } else {
    spuParams.value = row;
    await getTrademarkList();
    await getSaleAttrListAll();
  }
};

//  获取spu下所有品牌
const getTrademarkList = async () => {
  let resultTrademarkList = await reqTrademarkList();
  if (resultTrademarkList.code === 200) {
    allTrademarkList.value = resultTrademarkList.data;
  }
};

// 获取某一个spu的图片列表
const getSpuImageList = async (SpuId: number) => {
  let resultSpuImageList = await reqSpuImageList(SpuId);
  if (resultSpuImageList.code === 200) {
    imageList.value = resultSpuImageList.data;
    // 将imageList中的数据转换成fileList中的数据
    fileList.value = imageList.value.map((item) => {
      return {
        name: item.imgName,
        url: item.imgUrl,
      };
    });
  }
};

// 获取某一个spu的销售属性列表
const getSpuSaleAttrList = async (SpuId: number) => {
  let resultSpuSaleAttrList = await rqeSpuSaleAttrList(SpuId);
  if (resultSpuSaleAttrList.code === 200) {
    hasAttrList.value = resultSpuSaleAttrList.data;
  }
};

// 获取所有的销售属性列表
const getSaleAttrListAll = async () => {
  let resultSaleAttrListAll = await reqBaseSaleAttrList();
  if (resultSaleAttrListAll.code === 200) {
    attrListAll.value = resultSaleAttrListAll.data;
  }
};

// 定义一个响应式引用
let fileList = ref<UploadUserFile[]>([]);

// 监听imageList的变化  当imageList变化的时候  我们就要将imageList中的数据转换成fileList中的数据
// watch(
//   () => imageList.value,
//   (newImageList) => {
//     fileList.value = newImageList.map((item) => {
//       return {
//         name: item.imgName,
//         url: item.imgUrl,
//       };
//     });
//   },
// );

// 监听fileList的变化  当fileList变化的时候  我们就要将fileList中的数据转换成imageList中的数据
watch(
  () => fileList.value,
  (newFileList) => {
    imageList.value = newFileList.map((item) => {
      return {
        imgName: item.name,
        imgUrl: item.url,
      };
    });
  },
);

const dialogImageUrl = ref(""); // 图片预览地址
const dialogVisible = ref(false); // 图片预览弹窗

// 删除图片 uploadFile:当前删除的图片  uploadFiles:当前剩余的图片
const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
  console.log(uploadFile, uploadFiles);
};

// 预览图片 uploadFile:当前预览的图片
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url!; // 设置预览地址
  dialogVisible.value = true; // 打开预览弹窗
};

// 上传图片之前的钩子 uploadFile:当前上传的图片
const beforeUpload = (uploadFile: any) => {
  //必须是jpg或者png格式的图片
  const isJPG = uploadFile.type === "image/jpeg";
  const isPNG = uploadFile.type === "image/png";
  const isLt2M = uploadFile.size / 1024 / 1024 < 2;

  if (!isJPG && !isPNG) {
    // 上传的图片格式不正确
    ElMessage.error("上传的图片格式不正确,请上传jpg或者png格式的图片");
    return false;
  } else if (!isLt2M) {
    // 上传的图片大小超过2M
    ElMessage.error("上传的图片大小超过2M");
    return false;
  }

  console.log(isJPG, isPNG, isLt2M, (isJPG || isPNG) && isLt2M);
  // 上传的图片格式正确并且大小没有超过2M
  if ((isJPG || isPNG) && isLt2M) {
    return true;
  } else {
    return false;
  }
};

const inputVisible = ref(false);
const InputRef = ref<InstanceType<typeof ElInput>>();

// 关闭tag row:当前行数据  tag:当前tag
const handleClose = (row: any, tag: any) => {
  // 1.删除已经添加的销售属性列表中的数据
  row.spuSaleAttrValueList.splice(row.spuSaleAttrValueList.indexOf(tag), 1);
};

// 显示输入框 添加tag
const showInput = (row: SpuSaleAttr) => {
  // 1.将inputValue置为可见
  row.flag = true;
  // 2.将inputValue自动获取焦点
  nextTick(() => {
    // 3.获取焦点
    // 这个地方的InputRef是我们在el-input上面定义的ref="InputRef"
    // 虽然三个input框的ref都是InputRef 但是因为视角会导致其他两个input框获取不到焦点，input会消失，每次只会有一个input
    // ！的作用是非空判断
    InputRef.value!.input!.focus();
  });
};

//  回车 添加tag
const handleInputConfirm = (row: SpuSaleAttr) => {
  // 1.判断inputValue是否有值
  if (row.inputValue) {
    // 判断当前添加的tag是否已经存在
    if (
      //   some函数返回的是布尔值 find函数返回的是数组中满足条件的第一个元素
      row.spuSaleAttrValueList.some((item) => {
        return item.saleAttrValueName === row.inputValue;
      })
    ) {
      ElMessage.warning("该销售属性值已经添加过了");
      return;
    }

    // 2.将inputValue添加到spuSaleAttrValueList中
    row.spuSaleAttrValueList.push({
      baseSaleAttrId: row.baseSaleAttrId,
      saleAttrName: row.saleAttrName,
      saleAttrValueName: row.inputValue,
      spuId: row.spuId,
    });
  }
  // 3.将inputValue置为不可见
  row.flag = false;
  // 4.将inputValue置为空
  row.inputValue = "";
};

// 删除已经添加的销售属性列表中的数据
const deleteAttr = (row: any) => {
  // 1.删除已经添加的销售属性列表中的数据
  hasAttrList.value.splice(hasAttrList.value.indexOf(row), 1);
};

// 下拉框中是否显示已经添加的销售属性列表中的数据
let unSelectSaleAttrList = computed(() => {
  return attrListAll.value.filter((item) => {
    // 2.过滤已经添加的销售属性列表中的数据
    return !hasAttrList.value.some((saleAttr) => {
      return saleAttr.saleAttrName === item.name;
    });
  });
});

// 被选中的销售属性
let selectedAttr = ref<BaseSaleAttr>();

// 新增销售属性
let addAttr = () => {
  // 1.判断selectedAttr是否有值
  if (selectedAttr.value as BaseSaleAttr) {
    // 2.判断selectedAttr是否已经添加过
    if (
      hasAttrList.value.some((item) => {
        return item.saleAttrName === selectedAttr.value.name;
      })
    ) {
      ElMessage.warning("该销售属性已经添加过了");
      return;
    }
    // 3.将selectedAttr添加到hasAttrList中
    hasAttrList.value.push({
      saleAttrId: selectedAttr.value.id,
      baseSaleAttrId: selectedAttr.value.id,
      saleAttrName: selectedAttr.value.name,
      spuSaleAttrValueList: [],
    });
    selectedAttr.value = undefined;
  } else {
    ElMessage.warning("请选择销售属性");
    selectedAttr.value = undefined;
  }
};

// 定义组件名称
defineOptions({
  name: "SpuForm",
});

// 对父组件暴露方法
defineExpose({
  initData,
});
</script>

<template>
  <div>
    <!-- form 表单  -->
    <el-form label-width="100px" :model="spuParams">
      <el-form-item label="SPU名称">
        <el-input
          v-model="spuParams.spuName"
          placeholder="请输入SPU名称"
        ></el-input>
      </el-form-item>
      <el-form-item label="SPU品牌">
        <el-select v-model="spuParams.tmId">
          <el-option
            v-for="trademark in allTrademarkList"
            :key="trademark.id"
            :label="trademark.tmName"
            :value="trademark.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="SPU描述">
        <el-input
          type="textarea"
          v-model="spuParams.description"
          placeholder="请输入SPU描述"
        ></el-input>
      </el-form-item>
      <!--  spu 照片墙  -->
      <el-form-item label="SPU照片">
        <!--  v-model:file-list  适用于展示图片的
            action 上传图片的地址
            -->
        <el-upload
          v-model:file-list="fileList"
          action="/dev-api/admin/product/fileUpload"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :on-remove="handleRemove"
          :before-upload="beforeUpload"
        >
          <el-icon>
            <Plus />
          </el-icon>
        </el-upload>

        <el-dialog v-model="dialogVisible">
          <img w-full :src="dialogImageUrl" alt="Preview Image" />
        </el-dialog>
      </el-form-item>
      <el-form-item label="SPU销售属性">
        <el-select v-model="selectedAttr">
          <el-option
            v-for="saleAttr in unSelectSaleAttrList"
            :label="saleAttr.name"
            :value="saleAttr"
          ></el-option>
        </el-select>
        <el-button
          icon="plus"
          type="primary"
          class="add-btn"
          @click="addAttr"
          :disabled="!selectedAttr"
        >
          添加销售属性
        </el-button>

        <!--  展示已经添加的销售属性的table    -->
        <el-table border class="add-table" :data="hasAttrList">
          <el-table-column
            label="序号"
            type="index"
            width="80px"
            align="center"
          >
          </el-table-column>
          <el-table-column
            label="销售属性名称"
            align="center"
            prop="saleAttrName"
          >
          </el-table-column>
          <el-table-column
            label="销售属性值"
            align="center"
            prop="spuSaleAttrValueList"
          >
            <template #default="{ row }">
              <el-tag
                v-for="tag in row.spuSaleAttrValueList"
                :key="tag"
                class="mx-1 inline-input"
                closable
                :disable-transitions="false"
                @close="handleClose(row, tag)"
                style="margin-right: 10px"
              >
                {{ tag.saleAttrValueName }}
              </el-tag>
              <el-input
                v-if="row.flag"
                ref="InputRef"
                v-model="row.inputValue"
                class="ml-1 w-20 inline-input"
                size="small"
                @keyup.enter="handleInputConfirm(row)"
                @blur="handleInputConfirm(row)"
              />
              <el-button
                v-else
                class="button-new-tag ml-1"
                size="small"
                @click="showInput(row)"
              >
                + New Tag
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="操作" align="center">
            <template #default="{ row }">
              <el-button
                type="danger"
                size="small"
                icon="delete"
                title="删除"
                @click="deleteAttr(row)"
              >
              </el-button>
            </template>
          </el-table-column>
        </el-table>

        <el-button @click="submit" type="primary">保存</el-button>
        <el-button @click="cancel">取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<style scoped lang="scss">
.add-btn {
  margin-left: 10px;
}

.add-table {
  margin: 10px 0;
}

.inline-input {
  display: inline-block;
  width: auto;
}
</style>
